package markdown;


import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.nio.file.Files;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 将原md文件中所有图片下载到同一目录，并修改url为相对路径
 * 提取图片、清理多余图片
 */
public class BatchImgDownAndReplaceUtil {

    private final static String PROTOCOL = "file:" + File.separator;

    // 源.md文件
    private final static String ORIGIN_FILE_PATH = "F:\\学习项目\\资料整理\\整理中\\notepad使用\\notepad使用.md";
    // 新文件夹地址
    private static String TARGET_DIR_PATH = null;
    // 图片文件夹名称
    private final static String IMG_DIR = "media";

    public static void main(String[] args) throws Exception {

        File file = new File(ORIGIN_FILE_PATH);
        if (!file.exists() || !file.isFile()) {
            System.out.println("文件不存在");
            return;
        }

        String name = file.getName();
        int indexOf = name.lastIndexOf(".");
        String targetDirPath = file.getParent() + File.separatorChar + name.substring(0, indexOf) + System.currentTimeMillis();
        File targetDir = new File(targetDirPath);
        targetDir.mkdirs();
        TARGET_DIR_PATH = targetDirPath;

        // 读取一个文件，获取到内容
        String newContent = readFile(ORIGIN_FILE_PATH);

        // 写入到目标文件
        writeFile(newContent, TARGET_DIR_PATH + File.separatorChar + name);

        System.out.println("处理完成！");
    }

    /**
     * 通过文件名读取一个markdown文件
     */
    private static String readFile(String originFile) throws Exception {
        FileInputStream fis = new FileInputStream(originFile);
        final InputStreamReader isr = new InputStreamReader(fis, "UTF-8");
        BufferedReader bufferedReader = new BufferedReader(isr);
        String content = "";
        String line = null;
        while ((line = bufferedReader.readLine()) != null) {
            // 按行读取
            if (!line.isEmpty()) {
                // 处理图片
                line = handleImg(line);
            }
            content += line + "\r\n";
        }
        bufferedReader.close();
        return content;
    }

    /**
     * 判断该行是否有图片，有则提取并替换
     */
    private static String handleImg(String line) throws Exception {
        System.out.println(line);
        System.out.println("--------line--------");
        // 处理图片类型1： ![]()
        // copy至大佬的代码，原来不用正则也可以处理啊
        for (int i = 0; i < line.length(); i++) {
            if (i < line.length() - 4 && line.charAt(i) == '!' && line.charAt(i + 1) == '[') {
                int index1 = line.indexOf(']', i + 1);
                if (index1 != -1 && line.charAt(index1 + 1) == '(' && line.indexOf(')', index1 + 2) != -1) {
                    int index2 = line.indexOf(')', index1 + 2);
                    // [图片描述]
                    String picName = line.substring(i + 2, index1);
                    // (图片路径)
                    String picPath = line.substring(index1 + 2, index2).trim();
                    line = toDownImg(line, picPath);
                }
            }
        }

        // 处理图片类型2： <img src="../../../图片/我是图片.png" style="zoom:25%;" />
        line = handleImgTag(line);

        return line;
    }

    /**
     * 处理html类型的img标签
     * 使用正则提取
     */
    private static String handleImgTag(String line) throws Exception {
        Matcher mImage = Pattern.compile("<img.*?src\\s*=\\s*(.*?)[^>]*?>", Pattern.CASE_INSENSITIVE).matcher(line);
        while (mImage.find()) {
            // 得到<img />数据
            String imgTagStr = mImage.group();
            // 匹配<img>中的src数据
            Matcher m = Pattern.compile("\\s{1}src=[\'\"]([^\'\"]+)[\'\"]").matcher(imgTagStr);
            while (m.find()) {
                String picPath = m.group(1);
                System.out.println("提取img标签图片：" + picPath);
                line = toDownImg(line, picPath);
            }
        }
        return line;
    }

    /**
     * 将图片全部转为本地相对目录
     * 1.以http开头的下载
     * 2.本地图片copy待临时目录下
     */
    private static String toDownImg(String line, String picPath) throws Exception {
        // 保存原始地址，替换时使用
        String originPicPath = picPath;
        if (!picPath.isEmpty() && !picPath.startsWith("http")) {
            // 判断是相对路径，还是绝对路径
            // https://www.jb51.net/article/64518.htm
            if (picPath.startsWith("/") || picPath.indexOf(":") == 1) {
                // 绝对路径
            } else {
                // 相对路径转绝对路径
                // 使用该方法需要有协议头，比如http
                String absUrl = getAbsUrl(PROTOCOL + ORIGIN_FILE_PATH, picPath);
                // 切掉协议头
                picPath = absUrl.substring(PROTOCOL.length());
            }

            System.out.println("图片绝对路径：" + picPath);
            File file = new File(picPath);
            if (file == null || !file.exists() || file.isDirectory()) {
                // 可能url被编码过
                picPath = java.net.URLDecoder.decode(picPath, "UTF-8");
                file = new File(picPath);
                if (file == null || !file.exists() || file.isDirectory()) {
                    return line;
                }
            }
            System.out.println("图片需要上传：" + picPath);

            // 上传图片
            line = copyImg(line, originPicPath, file);
        } else {
            // 下载图片
            line = downImg(line, originPicPath);
        }
        return line;
    }

    /**
     * copy图片到新的临时目录，并替换图片路径
     */
    private static String copyImg(String line, String originPicPath, File file) {
        // 绝对路径
        String newImgPath_absolute = TARGET_DIR_PATH + File.separator + IMG_DIR + File.separator + file.getName();
        // 相对路径
        // String newImgPath_relative = IMG_DIR + File.separator + file.getName();
        String newImgPath_relative = IMG_DIR + "/" + file.getName();

        File parentFile = new File(newImgPath_absolute).getParentFile();
        if (!parentFile.exists()) {
            parentFile.mkdirs();
        }

        boolean b = true;
        try {
            Files.copy(file.toPath(), new File(newImgPath_absolute).toPath());
        } catch (IOException e) {
            e.printStackTrace();
            b = false;
        }

        if (b) {
            line = line.replace(originPicPath, newImgPath_relative);
        }

        return line;
    }

    /**
     * 下载网络图片到新的临时目录，并替换图片路径
     */
    private static String downImg(String line, String originPicPath) {
        // 绝对路径
        String ext = originPicPath.lastIndexOf(".") == - 1 ? "" : originPicPath.substring(originPicPath.lastIndexOf("."));
        String fileName = UUID.randomUUID().toString().replaceAll("-", "") + ext;
        String newImgPath_absolute = TARGET_DIR_PATH + File.separator + IMG_DIR + File.separator + fileName;
        // 相对路径 linux只能识别 /  windows都能识别
        // String newImgPath_relative = IMG_DIR + File.separator + fileName;
        String newImgPath_relative = IMG_DIR + "/" + fileName;

        File parentFile = new File(newImgPath_absolute).getParentFile();
        if (!parentFile.exists()) {
            parentFile.mkdirs();
        }

        boolean b = false;

        ReadableByteChannel rbc = null;
        FileOutputStream fos = null;
        try {
            URL website = new URL(originPicPath);
            HttpURLConnection urlCon = (HttpURLConnection) website.openConnection();
            // 指定超时时间，不指定在正式服务器会无限等待，212不会
            urlCon.setConnectTimeout(180000);
            urlCon.setReadTimeout(180000);

            rbc = Channels.newChannel(urlCon.getInputStream());
            fos = new FileOutputStream(newImgPath_absolute);
            fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
            b = true;
        } catch (Exception e) {
            System.out.println("下载异常：" + originPicPath);
            e.printStackTrace();
        } finally {
            if (fos != null) {
                try {
                    fos.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            if (rbc != null) {
                try {
                    rbc.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }

        if (b) {
            line = line.replace(originPicPath, newImgPath_relative);
        }

        return line;
    }

    /**
     * 相对路径转为绝对路径
     *
     * @param absolutePath 绝对路径
     * @param relativePath 相对路径
     * @return 绝对路径
     */
    private static String getAbsUrl(String absolutePath, String relativePath) throws Exception {
        URL absoluteUrl = new URL(absolutePath);
        URL parseUrl = new URL(absoluteUrl, relativePath);
        return parseUrl.toString();
    }

    /**
     * 将内容写到目标文件
     */
    private static void writeFile(String newContent, String targetFile) throws Exception {
        File file = new File(targetFile);
        FileOutputStream fos = new FileOutputStream(file);
        OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF-8");
        osw.write(newContent);
        osw.flush();
        osw.close();
    }

}
